Repository navigation
Start nspawn workers after reboot on RHEL and recover stopped workers - #437
hbc (bcho) with Copilot wants to merge 13 commits into
Conversation
Co-authored-by: bcho <1975118+bcho@users.noreply.github.com>
Co-authored-by: bcho <1975118+bcho@users.noreply.github.com>
Co-authored-by: bcho <1975118+bcho@users.noreply.github.com>
There was a problem hiding this comment.
🟡 Changes recommended
Worker failures can go undetected and unrecovered, while the new preflight check blocks online bootstrap before required packages can be installed.
2 open issues
What changed in this PR
This PR addresses the reboot-startup portion of #436 by making the Flex Node daemon request machines.target, allowing enabled nspawn workers to start even when RHEL presets disable the target.
Changes:
- Add
machines.targetdependencies to host and container daemon units. - Register a preflight check for target availability and enablement.
- Add checker tests, update service snapshots, and document preflight behavior.
| File | Description |
|---|---|
pkg/daemon/testdata/aks-flex-node-agent.service.golden |
Update the expected host-unit dependency. |
pkg/daemon/testdata/aks-flex-node-agent-arc.service.golden |
Update the expected Arc-enabled unit dependency. |
pkg/daemon/preflight.go |
Add target-state validation. |
pkg/daemon/preflight_test.go |
Test target states and daemon-unit dependencies. |
pkg/daemon/assets/aks-flex-node-agent.service |
Request worker startup through machines.target. |
pkg/daemon/assets/aks-flex-node-agent-container.service |
Add the same dependency for container deployments. |
pkg/cmd/preflight/preflight.go |
Register the new preflight check. |
docs/usage/operations.md |
Explain target-check errors and warnings. |
Review effort: Balanced
Philip Lombardi (plombardi89)
left a comment
There was a problem hiding this comment.
Thanks for this. The boot fix itself works. Requesting changes for the preflight check and some housekeeping.
Blocking
- The
machines-targetcheck fails preflight on a fresh host wheresystemd-containerisn't installed yet, although bootstrap installs it and unbounded's own checks only warn about it. Inline onpkg/daemon/preflight.go:37, with a reproducer on RHEL 9.8. - Housekeeping before merge:
- The description is out of date. It still lists the "Worker health" changes that 695b06b removed.
Fixes #436will close the issue, but only half of it is fixed. The issue's second request (the agent noticing a stopped worker instead of reporting success for three days) was dropped. Please useRefs #436and open a follow-up issue, or note on #436 that this part won't be done.- No
CHANGELOG.mdentry. There's an[Unreleased]section, and this change is user-facing: a fix (workers now start after reboot on RHEL) and a new preflight check.
Verified: Wants=machines.target. I tested it on systemd 252 (Rocky Linux 9.8, the same systemd as the RHEL 9.8 hosts in #436):
- The worker was the real
systemd-nspawn@.service, with only its process replaced bysleep. - The agent unit was the actual golden unit from
mainor from this PR, again with onlyExecStartreplaced. machines.targetwasdisabledandsystemd-nspawn@kube1.servicewas enabled, as on the reporter's hosts.- Each scenario was a reboot.
| Scenario | machines.target |
Worker | Agent |
|---|---|---|---|
Agent unit from main |
inactive | never started (reproduces #436) | active |
| Agent unit from this PR | active | active | active, without waiting for the worker |
PR's container-variant unit, containerd start fails |
active | active | not started (dependency failed) |
| Worker disabled and stopped on purpose, as unbounded does when it stops a machine | active | stays stopped | active |
The upgrade path also heals hosts that are already stuck. Writing the new unit and running daemon-reload alone starts nothing, but the agent restart that follows an upgrade starts machines.target and the stopped worker. Stopping the agent doesn't stop either of them.
After=machines.target: no change needed. Unbounded's own daemon unit has After= as well as Wants=. Adding it here would hold the agent until the worker's start finishes; I tested that, and a worker whose start fails doesn't block the agent. A start that hangs would hold it for up to the worker's start timeout, 90 seconds by default for the Type=notify nspawn unit. I found nothing in pkg/daemon that assumes the worker is up at startup, and the worker's pre-start/post-start hooks don't depend on the agent unit. So Wants= alone is the better choice here.
The remaining gap is a real reboot of a real RHEL host with a real nspawn worker, which the PR description already lists as outstanding.
|
Copilot address pr comments |
Co-authored-by: bcho <1975118+bcho@users.noreply.github.com>
Co-authored-by: bcho <1975118+bcho@users.noreply.github.com>
Co-authored-by: bcho <1975118+bcho@users.noreply.github.com>
|
Copilot resolve conflicts |
…target-issue # Conflicts: # CHANGELOG.md Co-authored-by: bcho <1975118+bcho@users.noreply.github.com>
Resolved the changelog conflict by merging |
Philip Lombardi (plombardi89)
left a comment
There was a problem hiding this comment.
Approving. The preflight fix is verified (details in the resolved thread), and the boot fix holds up on a real RHEL host (below).
Before merging, please update the PR's title and description. They still describe work that 695b06b removed:
- Title: drop "and recover stopped workers", for example "Start nspawn workers after reboot on RHEL".
- Body:
- remove the "Worker health" bullet
- update the "Preflight" bullet to the online/offline/containerized behavior
- replace "live RHEL reboot testing remains outstanding" (results below)
- check the changelog box
- Use
Refs #436instead ofFixes #436, and open a follow-up issue for the second request (the agent noticing a stopped worker). The test below reproduced it: with the worker down and the nodeNotReady, the agent kept loggingdecision=ReportSucceeded reason="goal state is applied". Merging withFixeswould close the issue with that still open.
Real RHEL host test. Setup:
- an Azure VM from
RedHat:RHEL:9_8-gen2, joined to a new AKS cluster with the repo's e2e token-join scripts - the boot fix from this PR (the unit files are unchanged since
69f1cc6) machines.targetdisabledby the RHEL preset, withsystemd-nspawn@kube1enabled under it, as in #436
Each row is a reboot unless noted:
| Test | machines.target |
Worker | Node |
|---|---|---|---|
| This PR's unit | active (still disabled) |
started; its kubelet was running 13 s after boot | Ready |
Pre-PR Wants= line restored |
inactive | never started | NotReady; the agent kept reporting ReportSucceeded |
| Agent restart, as after an upgrade, with the worker down (no reboot) | started | started | Ready again |
| The unit as the agent rewrote it at startup | active | started | Ready |
Also from that host:
Wants=alone is enough. The worker was active 3 s before the agent even withoutAfter=machines.target, because the agent also waits fornetwork-online.target.- The project's own e2e token-join flow hits the old preflight error on RHEL. It installs host packages only with
apt-get, so it reached preflight withoutsystemd-containerand failed onmachines-target. With the current head that's a warning.
Separate from this PR: the agent crash-loops on RHEL with SELinux enforcing. Enforcing is the default on Azure's RHEL images, so I set the test VM to permissive to get through the test.
- The error:
initialize agent binary layout: initialize daemon compatibility symlink: symlink /opt/unbounded/agent/lib/aks-flex-node/aks-flex-node-current /opt/unbounded/agent/bin/.aks-flex-node…/tmp.symlink: permission denied - A/B test: enforcing fails, permissive works.
- Context: the agent runs as
init_t, and its binary under/opt/unbounded/agent/libis labeledlib_t. No AVC is logged, even withdontauditrules disabled. - Suggestion: this probably deserves its own issue.


Summary
RHEL presets leave
machines.targetdisabled, preventing workers from starting after reboot. The daemon still reported success because it checked persisted settings, not worker liveness.Wants=machines.targetto host and container daemon units.Validation
Full test suite, affected-package race tests, vet, documentation checks, build, and CLI smoke test passed. CodeQL and secret scans were clean.
golangci-lintwas unavailable; live RHEL reboot testing remains outstanding.Changelog
UnreleasedinCHANGELOG.md, or this change does not require a changelog entry.